package com.mall.ums.service.impl;

import com.alibaba.nacos.common.utils.IPUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mall.model.domain.dto.UpdatePasswordParamDto;
import com.mall.model.domain.ums.*;
import com.mall.model.domain.vo.AdminInfoVo;
import com.mall.model.domain.vo.ErrorResult;
import com.mall.ums.exception.BusinessException;
import com.mall.ums.mapper.AdminMapper;
import com.mall.ums.service.*;
import com.mall.utils.IpUtil;
import com.mall.utils.JwtUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author clutchcitylee
 * @create 2023-03-12-9:41
 */
@Service
public class AdminServiceImpl extends ServiceImpl<AdminMapper, Admin> implements AdminService {

    @Autowired
    private AdminPermissionRelationService adminPermissionRelationService;

    @Autowired
    private AdminRoleRelationService adminRoleRelationService;

    @Autowired
    private MenuService menuService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private AdminLoginLogService adminLoginLogService;

    @Override
    @Transactional
    public boolean removeUser(Integer id) {
        try {
            //删除admin表中数据
            this.removeById(id);
            //删除admin与permission关系表中数据
            LambdaQueryWrapper<AdminPermissionRelation> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(AdminPermissionRelation::getAdminId, id);
            adminPermissionRelationService.remove(lambdaQueryWrapper);
            //删除admin与role关系表中数据
            LambdaQueryWrapper<AdminRoleRelation> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
            lambdaQueryWrapper1.eq(AdminRoleRelation::getAdminId, id);
            adminRoleRelationService.remove(lambdaQueryWrapper1);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    @Transactional
    public Map loginVerification(String username, String password, HttpServletRequest request) {
        //根据用户名查询数据
        LambdaQueryWrapper<Admin> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Admin::getUsername, username);
        Admin admin = this.getOne(lambdaQueryWrapper);
        //用户名不存在，抛出异常
        if (admin == null) {
            throw new BusinessException(ErrorResult.fail());
        }
        //bcrypt验证加密密码
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //密码错误，抛出异常
        if (!encoder.matches(password, admin.getPassword())) {
            throw new BusinessException(ErrorResult.loginError());
        }
        //设置最后登录时间
        LambdaUpdateWrapper<Admin> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(Admin::getId, admin.getId());
        wrapper.set(Admin::getLoginTime, new Date());
        this.update(admin, wrapper);
        //记录登录日志
        String ip = IpUtil.getIpAddr(request);
        String address = IpUtil.getAddressByIP(ip);
        String userAgent = request.getHeader("User-Agent");
        AdminLoginLog adminLoginLog = new AdminLoginLog();
        adminLoginLog.setAdminId(admin.getId());
        adminLoginLog.setCreateTime(new Date());
        adminLoginLog.setIp(ip);
        adminLoginLog.setAddress(address);
        adminLoginLog.setUserAgent(userAgent);
        adminLoginLogService.save(adminLoginLog);
        //验证成功，存入token
        Map map = new HashMap<>();
        map.put("id", admin.getId());
        map.put("username", username);
        String token = JwtUtils.getToken(map);
        Map tokenMap = new HashMap();
        tokenMap.put("token", token);
        tokenMap.put("tokenHead", "Bearer ");
        return tokenMap;
    }

    @Override
    public AdminInfoVo getUserInfo(Long id) {
        AdminInfoVo vo = new AdminInfoVo();
        LambdaQueryWrapper<Admin> lqw = new LambdaQueryWrapper<>();
        lqw.eq(Admin::getId, id);
        Admin admin = this.getOne(lqw);
        BeanUtils.copyProperties(admin, vo);
        LambdaQueryWrapper<Menu> lqw2 = new LambdaQueryWrapper<>();
        lqw2.eq(Menu::getHidden, 0);
        lqw2.orderByDesc(Menu::getCreateTime);
        List<Menu> menus = menuService.list(lqw2);
        vo.setMenus(menus);
        List<Role> roles = roleService.list();
        vo.setRoles(roles);
        return vo;
    }

    @Override
    public Admin register(Admin admin) {
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Admin::getUsername, admin.getUsername());
        int count = this.count(wrapper);
        if (count > 0) {
            throw new BusinessException(ErrorResult.userNameError());
        }
        admin.setCreateTime(new Date());
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (admin.getPassword() == null) {
            String password = encoder.encode("123456");
            admin.setPassword(password);
        }
//        admin.setStatus(1);
        this.save(admin);
        return admin;
    }

    @Override
    public boolean updateAdminById(Admin admin, Integer id) {
        try {
            LambdaUpdateWrapper<Admin> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(Admin::getId, id);
            this.update(admin, wrapper);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public void updatePassword(UpdatePasswordParamDto updatePasswordParamDto) {
        LambdaQueryWrapper<Admin> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Admin::getUsername, updatePasswordParamDto.getUsername());
        Admin admin = this.getOne(wrapper);
        //用户名错误，抛出异常
        if (admin == null) {
            throw new BusinessException(ErrorResult.fail());
        }
        //输入的旧密码与原密码不一致，抛出异常
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(updatePasswordParamDto.getOldPassword(), admin.getPassword())) {
            throw new BusinessException(ErrorResult.passwordError());
        }
        //验证完成，将新密码加密后更新
        String newPassword = encoder.encode(updatePasswordParamDto.getNewPassword());
        admin.setPassword(newPassword);
        this.updateById(admin);
    }

    @Override
    public void updateStatus(Integer id, Integer status) {
        Admin admin = this.getById(id);
        admin.setStatus(status);
        this.updateById(admin);
    }
}
